package org.example.viteVantDemo.ctrl.point;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.example.viteVantDemo.Application;
import org.example.viteVantDemo.constants.ApiCodeEnum;
import org.example.viteVantDemo.entity.TParam;
import org.example.viteVantDemo.entity.UserAssets;
import org.example.viteVantDemo.entity.UserAssetsLog;
import org.example.viteVantDemo.entity.UserInfo;
import org.example.viteVantDemo.mapper.UserAssetsLogMapper;
import org.example.viteVantDemo.mapper.UserAssetsMapper;
import org.example.viteVantDemo.mapper.UserMapper;
import org.example.viteVantDemo.model.ApiRes;
import org.example.viteVantDemo.model.OnlinePerson;
import org.example.viteVantDemo.model.TransRequest;
import org.example.viteVantDemo.model.TransactionResponse;
import org.example.viteVantDemo.security.VantUser;
import org.example.viteVantDemo.util.VantUserUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

@Slf4j
@RestController
@RequestMapping("/point")
public class PointController {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserAssetsMapper assetsMapper;

    @Autowired
    private UserAssetsLogMapper assetsLogMapper;

    @GetMapping("/test")
    public ApiRes test() {
        return ApiRes.ok();
    }

    @GetMapping("/queryInfo")
    public ApiRes queryInfo(Authentication authentication) {
        VantUser vantUser = VantUserUtils.getVantUser(authentication);
        Integer id = vantUser.getId();

        // 1 获取余额
        LambdaQueryWrapper<UserAssets> assetsQueryWrapper = new LambdaQueryWrapper<>();
        assetsQueryWrapper.eq(UserAssets::getUserId, id);
        UserAssets userAssets = assetsMapper.selectOne(assetsQueryWrapper);
        Map<String, Object> result =new HashMap<>();
        result.put("balance", userAssets.getFundBalance());

        // 2 获取在线用户
        LambdaQueryWrapper<UserInfo> userInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userInfoLambdaQueryWrapper.eq(UserInfo::getVersion, Application.getVersion());
        List<UserInfo> userInfos = userMapper.selectList(userInfoLambdaQueryWrapper);
        List<OnlinePerson> dataList = userInfos.stream()
                .filter(v -> !v.getId().equals(id))
                .map(v -> new OnlinePerson(v.getId(), v.getAvatar(), v.getName()))
                .collect(Collectors.toList());
        result.put("onlinePersons", dataList);
        result.put("username", vantUser.getUsername());
        result.put("avatar", vantUser.getAvatar());
        result.put("version", vantUser.getVersion());
        return ApiRes.ok(result);
    }


    @GetMapping("/queryTransactionInfo")
    public ApiRes queryTransactionInfo(Authentication authentication) {
        VantUser vantUser = VantUserUtils.getVantUser(authentication);
        List<TParam> list = userMapper.queryAssetsType("assets_code");
        Map<String, String> typeParam = list.stream().collect(Collectors.toMap(TParam::getCode, TParam::getValue));
        List<TransactionResponse> results= assetsLogMapper.queryAssetsLog(vantUser.getId());
        for (TransactionResponse userAssetsLog : results) {
            String title = userAssetsLog.getTitle();
            String value = typeParam.get(userAssetsLog.getAssetsCode());
            title = title + "·" + value;
            if (userAssetsLog.getStatus() == 1) {
                title = title + "(已退款)";
            }

            // 转入且未退还
            if(TransRequest.TYPE_TRANS_IN.equals(userAssetsLog.getAssetsCode()) && userAssetsLog.getStatus() == 0) {
                userAssetsLog.setBackType(1);
            }
            userAssetsLog.setTitle(title);
        }
        return ApiRes.ok(results);
    }

    /**
     *  发起转账
     *
     * @return
     */
    @PostMapping("/trans")
    @Transactional
    public ApiRes trans(Authentication authentication, @RequestBody TransRequest request) {
        VantUser vantUser = VantUserUtils.getVantUser(authentication);
        BigDecimal lastBalance;
        lastBalance = doTransAmount(request, vantUser, TransRequest.TYPE_TRANS_IN, TransRequest.TYPE_TRANS_OUT);
        return ApiRes.ok(lastBalance);
    }

    @GetMapping("/refund/{assetsLogId}")
    @Transactional
    public ApiRes back(Authentication authentication , @PathVariable("assetsLogId")Integer assetsLogId) {
        UserAssetsLog userAssetsLog = assetsLogMapper.selectById(assetsLogId);
        if (userAssetsLog == null) {
            return ApiRes.fail(ApiCodeEnum.DB_RECORD_ERROR);
        }
        VantUser vantUser = VantUserUtils.getVantUser(authentication);
        Integer userId = userAssetsLog.getToUserId();
        if (!userId.equals(vantUser.getId())) {
            return ApiRes.fail(ApiCodeEnum.DB_RECORD_ERROR);
        }
        Integer toUserId = userAssetsLog.getFromUserId();
        TransRequest request = new TransRequest();
        request.setAmount(userAssetsLog.getAmount());
        request.setToId(toUserId);

        doTransAmount(request, vantUser, TransRequest.TYPE_BACK_IN, TransRequest.TYPE_BACK_OUT);
        userAssetsLog.setStatus(1);
        assetsLogMapper.updateById(userAssetsLog);
        return ApiRes.ok();
    }

    private BigDecimal doTransAmount(TransRequest request,
                                     VantUser vantUser,
                                     String inType,
                                     String outType) {
        BigDecimal lastBalance;
        synchronized (this) {
            LambdaQueryWrapper<UserAssets> assetsQueryWrapper = new LambdaQueryWrapper<>();
            assetsQueryWrapper.eq(UserAssets::getUserId, vantUser.getId());
            UserAssets userAssets = assetsMapper.selectOne(assetsQueryWrapper);
            BigDecimal fundBalance = userAssets.getFundBalance();
            lastBalance = fundBalance.subtract(request.getAmount());
            assetsMapper.updateBalanceByUserId(userAssets.getUserId(), lastBalance);
            assetsQueryWrapper.clear();
            assetsQueryWrapper.eq(UserAssets::getUserId, request.getToId());
            UserAssets userAssetsTo = assetsMapper.selectOne(assetsQueryWrapper);
            BigDecimal fundBalanceTo = userAssetsTo.getFundBalance();
            BigDecimal lastBalanceTo = fundBalanceTo.add(request.getAmount());
            assetsMapper.updateBalanceByUserId(userAssetsTo.getUserId(), lastBalanceTo);
            String assetsSerialNo = UUID.randomUUID().toString().replaceAll("-", "");
            // 收款
            UserAssetsLog logIn = new UserAssetsLog();
            logIn.setFromUserId(userAssets.getUserId());
            logIn.setToUserId(userAssetsTo.getUserId());
            logIn.setAmount(request.getAmount());
            logIn.setStartBalance(fundBalanceTo);
            logIn.setEndBalance(lastBalanceTo);
            logIn.setAssetsCode(inType);
            logIn.setAssetsSerialNo(assetsSerialNo);
            assetsLogMapper.insert(logIn);
            // 付款
            UserAssetsLog logOut = new UserAssetsLog();
            logOut.setFromUserId(userAssetsTo.getUserId());
            logOut.setToUserId(userAssets.getUserId());
            logOut.setAmount(request.getAmount().negate());
            logOut.setStartBalance(fundBalance);
            logOut.setEndBalance(lastBalance);
            logOut.setAssetsCode(outType);
            logOut.setAssetsSerialNo(assetsSerialNo);
            assetsLogMapper.insert(logOut);
        }
        return lastBalance;
    }
}
